package cn.zhxu.toys.util;

import java.util.Arrays;

public class NumUtils {

    public static final int RADIX_62 = 62;

    public static final int RADIX_256 = 256;


    /**
     * 62进制转换
     * @param data 序号低的为高位，序号高的为低位,最多5字节
     * @return
     */
    public static int from62Num(byte... data) {
        if (data.length > 5) {
            throw new IllegalArgumentException("the max length is 5 of the data param: " + Arrays.toString(data));
        }
        int sum = 0;
        int scale = 1;
        for (int i = data.length - 1; i >=0; i--) {
            sum += from62(data[i]) * scale;
            scale *= RADIX_62;
        }
        return sum;
    }

    /**
     * 判断一个字节数组是否不是62进制数
     * @param data
     * @return
     */
    public static boolean not62Num(byte... data) {
        if (data.length > 5) {
            return true;
        }
        for (byte b : data) {
            if (b < 0x30 ||  b > 0x7a
                    || (0x39 < b  && b < 0x41)
                    || (0x5a < b  && b < 0x61)) {
                return true;
            }
        }
        return false;
    }

    /**
     * int 值转 62 进制字节数组
     * @param value
     * @param length
     * @return
     */
    public static byte[] to62Num(int value, int length) {
        if (value < 0) {
            throw new IllegalArgumentException("the value param can not be negative: " + value);
        }
        if (length < 1) {
            throw new IllegalArgumentException("the length param must greater than 0: " + value);
        }
        byte[] bytes = new byte[length];
        int index = length - 1;
        while (value > 0 && index >= 0) {
            byte val = to62(value % RADIX_62);
            bytes[index] = val;
            value = value / RADIX_62;
            index--;
        }
        while (index >= 0) {
            bytes[index] = 0x30;
            index--;
        }
        return bytes;
    }

    /**
     * 无符号整数
     */
    public static int unsigned(byte value) {
        if (value >= 0) {
            return value;
        }
        return 256 + value;
    }

    /**
     * 256进制转换
     * @param data 序号低的为高位，序号高的为低位,最多5字节
     * @return
     */
    public static int from256Num(byte... data) {
        if (data.length > 4) {
            throw new IllegalArgumentException("the max length is 4 of the data param: " + Arrays.toString(data));
        }
        int sum = 0;
        int scale = 1;
        for (int i = data.length - 1; i >=0; i--) {
            sum += unsigned(data[i]) * scale;
            scale <<= 8;
        }
        return sum;
    }

    /**
     * int 值转 256 进制字节数组
     * 大端模式：数据的高字节保存在内存的低地址中，而数据的低字节保存在内存的高地址中
     * @param value
     * @param length
     * @return
     */
    public static byte[] to256Num(long value, int length) {
        if (value < 0) {
            throw new IllegalArgumentException("the value param can not be negative: " + value);
        }
        if (length < 1) {
            throw new IllegalArgumentException("the length param must greater than 0: " + value);
        }
        byte[] bytes = new byte[length];
        while (length > 0) {
            length--;
            bytes[length] = (byte) (value >> (8 * (bytes.length - length - 1)) & 0xFF);
        }
        return bytes;
    }

    public static byte[] longToBytes(long values, int length) {
        byte[] buffer = new byte[length];
        for (int i = 0; i < length; i++) {
            int offset = 64 - (i + 1) * 8;
            buffer[i] = (byte) ((values >> offset) & 0xff);
        }
        return buffer;
    }

    private static int from62(byte b) {
        if (0x30 <= b && b <= 0x39) {
            return b - 0x30;
        }
        if (0x61 <= b && b <= 0x7a) {
            return b - 0x57;
        }
        if (0x41 <= b && b <= 0x5a) {
            return b - 0x1d;
        }
        throw new IllegalArgumentException(b + " is not a num char");
    }


    public static byte to62(int v) {
        if (0 <= v && v <= 9) {
            return (byte) (v + 0x30);
        }
        if (10 <= v && v <= 35) {
            return (byte) (v + 0x57);
        }
        if (36 <= v && v <= 61) {
            return (byte) (v + 0x1d);
        }
        throw new IllegalArgumentException(v + " can not cast to 62 Num");
    }

}
